home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 4 / Amiga Tools 4.iso / tools / netzwerk / tcp-ip / usno / docs / interex.paper < prev    next >
Encoding:
Text File  |  1996-02-26  |  16.5 KB  |  335 lines

  1.  
  2.                 USING BSD IPC TO SYNCHRONIZE SYSTEM TIMES
  3.  
  4.                                Wendy King
  5.                             Richard Schmidt
  6.                          U.S. Naval Observatory
  7.                          Time Service Department
  8.                        34th & Massachusetts Ave., NW
  9.                         Washington, DC  20392-5100
  10.  
  11.  
  12.  
  13.  
  14. The Time Service Department of the U.S. Naval Observatory maintains a
  15. number of Hewlett Packard precision cesium-beam frequency standards in a
  16. system providing the USNO Master Clock.  Comparisons are made in
  17. nanosecond units and are monitored on a network of HP computers whose
  18. system clocks have in the past differed by MINUTES of time!  Aside from
  19. the obvious irony there are very good reasons for wanting uniform time
  20. in an ensemble of computers.  Processes distributed across a network of
  21. machines may need synchronized access to shared files.  File management
  22. across NFS mounts, as with the makefile utility, may depend on
  23. reasonably close system time agreement.  Time synchronization becomes
  24. even more important when independent machines must acquire and share
  25. real-time data.
  26.  
  27. But the crystal clocks in workstations are inherently unstable.  Drift
  28. rates of up to +/- 5 seconds per day are reported for the HP9000/300s.
  29.  
  30. We have developed a simple clock synchronization scheme based on the
  31. concept of a "time server" host which is kept on Master Clock time via a
  32. serial link, and an unlimited number of networked client machines which
  33. each set their system clocks to server time over a TCP/IP network.  The
  34. time setting process is auto-scheduled as a daily task with cron.
  35.  
  36. Hewlett-Packard 9000's and 1000's, Sun workstations, and DEC hosts,
  37. among others, support a system of interprocess communication known as
  38. the "Berkeley Software Distribution."  BSD IPC enables process
  39. communication via addressable sockets.  Data packets can be written to
  40. and read from sockets much like normal files.  Internet stream sockets
  41. are specifiable by the Internet address of a host and the number of a
  42. TCP or UDP port, enabling communications across local and wide area
  43. networks.
  44.  
  45. Our implementation of time syncronization uses Berkeley stream sockets,
  46. providing reliable, sequenced, flow-controlled communication of byte
  47. streams which are always received in the order that they are sent (2).
  48. TCP provides the underlying transmission protocol.
  49.  
  50. Networked time synchronization originates from a designated server host
  51. whose system clock is set to an external source.  At the U.S. Naval
  52. Observatory in Washington, an HP9000/835 and two HP1000/A990's obtain
  53. time from redundant serial links to USNO Master Clock systems 1 and 2.
  54.  
  55.  
  56.  
  57. On all our systems, the time is set to within one second, which is well
  58. within the accuracy needs of cron-scheduled processes. (Cron schedules
  59. only to one minute precision).  On the HP1000 systems, the time is set
  60. using the Master Clock link during the daily, automatic, re-boot, and
  61. the accuracy we achieve is less than 1/4 of a second.  Our A990 systems
  62. are used for real-time data acquisition and instrument control, and we
  63. can schedule processes to a tenth of a second accuracy.
  64.  
  65. A server process called "timesrv" resides on the server hosts.  It
  66. provides current system time on request via the TCP/IP network.  On the
  67. Unix system timesrv relies on the internet daemon "inetd" to be alert to
  68. activity on timesrv's particular socket port.  On the RTE systems, the
  69. internet daemon "inetd" only watches for Mail/1000 connection requests,
  70. and any NET IPC user applications that may have been installed.  The
  71. "timesrv" program on RTE must do the work of "inetd" for itself.
  72.  
  73. Any networked client wanting the server's time of day simply requests a
  74. connection to timesrv and reads back current time.  The client then
  75. calls the system stime() routine to set its system clock to the received
  76. time.  We did not develop a set-time program for the HP1000 systems
  77. because they have their own serial link to the Master Clock.
  78.  
  79. An auxilliary program, "timecheck", enables any user to check his system
  80. time against that of the time server.  Corrections are not made for
  81. network propagation or response delays.  We have tested Internet delays
  82. between Washington, D.C and Richmond, Florida, and we have never failed
  83. to achieve 1-second accuracy.  The initial connection request can take
  84. several (sometimes many) seconds, but once the connection is
  85. established, the time packet (4-bytes) is consistently received within
  86. one second.  We have also never failed to get one-second accuracy
  87. between any of our systems on the USNO LAN.
  88.  
  89. Time transfer from the time server host to a client is initiated at the
  90. client end.  The programs "time_set" or "TimeCheck" run on the client side,
  91. communicating with the program "timesrv" on the server host.  The client
  92. program performs nearly all of the work, which is as it should be.  It
  93. must request a connection to the server, receive back a 4-byte time
  94. value, shutdown the connection, and set the local system time or display
  95. the difference between the server's time and the local system time.  This
  96. is done with appropriate calls to the BSD IPC library.
  97.  
  98. The BSD IPC library is written in C.  It is a library of functions which
  99. can be called to interface with the OSI ISO transport layer.  As long as
  100. the client or server is written in C, using the BSD IPC library does not
  101. present any special problems.  For HP1000 systems which do not have a C
  102. compiler, FORTRAN or Pascal may be used, and HP has provided routines
  103. and code examples to handle pointers and structure data types which are
  104. not intrinsic, particularly to FORTRAN.  We used FORTRAN for the client
  105. and server on our RTE systems.
  106.  
  107.  
  108. The HP NS product includes examples of programs in C, FORTRAN, and Pascal,
  109. as well as the necessary "include" files with the BSD data types defined.
  110. To maintain consistency, our RTE systems all have a global /include
  111. directory which contains all the files in the NS product that were
  112. supplied in the /ns1000/include sub-directory.  All the data types
  113. referred to in this paper can be found in the /include/sockets.ftni or
  114. /include/sockets.h files.
  115.  
  116.  
  117. USING BSD UTILITIES AND CALLS
  118.  
  119. Function "gethostbyname" is called with a hostname argument known either
  120. via a local hosts file, a domain nameserver, or through the yellow pages
  121. (Network Information Services).  Returned is a pointer to a "hostent"
  122. structure, which contains among its elements the network (IP) address of
  123. the specified host.
  124.  
  125. The FORTRAN client program on the RTE system must use some special
  126. tricks to dereference the pointer and extract the 32-bit value from an
  127. array of 16-bit elements.  The value returned by gethostbyname is a
  128. pointer to a structure.  Since FORTRAN does not allow structures,
  129. offsets must be used to get the values from the structure fields.  The
  130. IP Address, which is the value we need, is referenced by the first element
  131. in an array of pointers in the fourth field of the hostent structure. (See
  132. /ns1000/include/sockets.ftni).
  133.  
  134. In order to dereference pointers returned by the BSD IPC functions, the
  135. entire data segment is declared to be an array.  The pointer is then
  136. used as an index into the array to obtain the value.  As shown in Figure
  137. 1, the alias directive is used to name an array as a common block
  138. starting from absolute address 0. This is followed by a COMMON
  139. declaration of the same name, and the elements of this common block are
  140. declared as an array.  FORTRAN does no array bounds check, so this array
  141. can be indexed with any value. (See the FORTRAN 77 manual).
  142.  
  143. Since, in the case of the hostent structure, each field is a 16-bit
  144. integer, X = mem(HostPtr + 4) gives the value of H_ADDR_LIST in X.  The
  145. first element of this array is the pointer to the IP Address of the Time
  146. Server Host, so Y = mem(x) returns the pointer to the IP Address.  Unix
  147. systems declare this as a character pointer, and since the IP Address is
  148. guaranteed to be word aligned, dividing it by 2 gives the word address,
  149. (Z = Y/2).  The 32-bit IP Address could be accessed from two memory
  150. locations, mem(z) and mem(z+1), but the double load instruction will
  151. transfer a 32-bit quantity in one step, hence (IpAddr = dld(mem(z))).
  152. The statement which puts this all together is shown in Figure 1. (See
  153. /ns1000/examples/bsdclient.ftn).
  154.  
  155. Figure 1.  Handling pointers and structures in FORTRAN
  156.  
  157. $alias dld = '.DLD',direct
  158. $alias /mem/ = 0
  159.        Common /mem/mem(0:1)
  160.        Integer mem
  161.        Integer HostPtr
  162.        Integer*4 dld
  163.        Integer*4 IPAddr
  164.        Integer*2  IHostName(32),IService(4)
  165.        Character  CHostName*64 ,CService*8
  166.        Equivalence (IHostName,CHostName),(IService,CService)
  167.  
  168.        i = TrimLen(CHostName) + 1
  169.        CHostName(i:i) = Char(0)
  170.        HostPtr = GetHostByName(ByteAdrOf(IHostName(1),0))
  171.        IPAddr  = dld(mem(mem(mem(HostPtr + 4))/2))
  172.  
  173.        i = TrimLen(CService) + 1
  174.        CService(i:i) = Char(0)
  175.  
  176.        ServPntr = GetServByName(ByteAdrof(IService,0),NULL)
  177.        Serv_Port = mem(ServPntr + 2)
  178.  
  179. Next, "getservbyname" is called with argument "timesrv", the server's
  180. time serving program.  Getservbyname merely searches the local
  181. /etc/services file for the dedicated port associated with the service
  182. "timesrv."  That port number is placed in a "servent" type structure,
  183. and a pointer to that structure is returned.
  184.  
  185. In Figure 1, the last two lines show how the pointer to the service
  186. port number is dereferenced in FORTRAN.  The value we want is in the
  187. third field of the servent structure. (See /ns1000/include/socket.ftni).
  188. Note also in Figure 1, the statements which place a null character at
  189. the end of each string which is passed as an argument.  In C, all
  190. character strings must be terminated with a null character.
  191.  
  192. A call to "socket" creates the socket as an AF_INET family member (for
  193. Internet connections) and type SOCK_STREAM, a full-duplex byte stream
  194. connection.
  195.  
  196. Function "connect" is called to make the actual connection.  Now the
  197. remote time server springs into action.  An entry in the server's
  198. /etc/services file links activity on timesrv's designated port with the
  199. timesrv service:
  200.  
  201.      timesrv xxxxx/tcp myalias
  202.  
  203. where "xxxxx" is the assigned port number agreed between server and all
  204. clients.  On the HP-UX systems, a related entry in /etc/inetd.conf enables
  205. assigning responsibility for monitoring that activity with the inetd
  206. program, eliminating the need for explicit daemons cluttering up the
  207. process table.  On the RTE systems we are forced to clutter up the process
  208. table, since the RTE inetd does not "do" berkeley sockets.  The format of
  209. the /etc/inetd.conf entry on the HP-UX systems is
  210.  
  211.      timesrv stream tcp nowait root /usr/local/bin/timesrv timesrv
  212.  
  213. describing the service, its type of socket, protocol, mode of activity,
  214. effective user id, path to the executable program, and name.
  215.  
  216. On the RTE system, a global directory /etc was created and the
  217. "services", "hosts", "protocols", and "networks" files were ftp'd from
  218. the HP-UX system.  This maintained consistency (everyone has all the
  219. same entries) and if HP does provide further enhancements of ARPA
  220. services for RTE, we will be ready!  No changes were required for these
  221. files on the RTE system.  The inetd.conf file already existed in the
  222. /system directory for Mail/1000, but is not involved with this
  223. application since inetd on RTE does not service BSD at Revision 5.27.
  224.  
  225. On the HP-UX system, the time server program consists of only three
  226. operations: a call to the Unix "time" function to obtain the system time
  227. in seconds from epoch in the format of a long int , a "send" to pass out
  228. the time, and a shutdown to close the connection.  As inetd communicates
  229. via standard input (stdin), the file descriptor for send is zero.
  230.  
  231. On the RTE system, the time server program must do everything that the
  232. HP-UX inetd does.  This includes a call to get a socket, a call to bind
  233. the socket to the timesrv port number, a call to establish a listen
  234. queue, and a call to accept connections.  The RTE time server is a
  235. daemon.  It looks for connection requests, creates a new socket for a
  236. requesting client, gets the system time, sends it through the new socket
  237. to the client, shuts down the new socket, and returns to accept the next
  238. request on the original socket.  We can break this infinite loop by
  239. setting the breakflag and then initiating a request.
  240.  
  241. The RTE time server also moves itself to system session, and logs all
  242. messages to a log file in the /system directory.  This proved helpful to
  243. the frazzled system manager who needed to troubleshoot failures some
  244. time after the event(s).  Every time the RTE time server services a
  245. request, it checks the breakflag, closing its log file and terminating
  246. gracefully if the breakflag is set.
  247.  
  248. As soon as the client sees a successful connection, it calls "recv" to
  249. read the 4-byte time value (long seconds from the beginning epoch).  The
  250. "ntohl" function is used to insulate the program from low-endian vs.
  251. high-endian byte preferences.
  252.  
  253. At last the "stime" function is used to set the system time to the
  254. received value.
  255.  
  256. In addition to the timesrv server program and the time_set client
  257. program, a variant of time_set called "timecheck" follows all of the
  258. steps of time_set, but rather than setting local system time, it simply
  259. reports the difference between the local time and the server's time.
  260.  
  261. The HP1000 client TimeCheck program approaches the connection process a
  262. little differently.  Since this program is typically run interactively,
  263. blocking mode (the default) caused problems when requests did not
  264. complete correctly.  So, the TimeCheck client uses non-blocking mode on
  265. its socket which necessitates the use of the Select() function to check
  266. for successfull completion of requests such as Connect() and Recv().
  267. The Select() function is the only one which accepts a user defined time
  268. out value, allowing the user's program to handle any event and continue
  269. (or terminate) gracefully.
  270.  
  271. In our implementation of these programs, our HP-UX clients schedule
  272. their timesetting requests via "cron".  It should be noted that prior to
  273. changing the system time, cron must kill itself on the client and also
  274. on any cnodes clustered to it.  A shell script which performs this
  275. suicidal act and then returns cron to life is included in the source
  276. distribution.
  277.  
  278. If you reset the system time on an RTE system, it is necessary to set up
  279. a command file to "of" all user processes and to shutdown ns/1000 before
  280. setting the time.  We tested the consequences of setting the RTE system
  281. "on the fly" and found that time scheduled processes were randomly
  282. adjusted or not, with no discernable pattern.
  283.  
  284. For RTE programmers (especially FORTRAN), there are a few documentation
  285. "bugs" to watch out for in the BSD IPC Reference Manual (NS-ARPA/1000,
  286. Volume 9, PN#91790-90060 E0891).
  287.  
  288. First, a library called HPC.LIB is required to link BSD programs.  We
  289. found the only way to link a BSD program (examples included) without an
  290. undefined symbols prompt was to create a .lod file for link which tells
  291. it to search the HPC.LIB after the first EN.  To relocate errnodec.rel
  292. along with the main program as suggested in the manual did not work.
  293. Because of the order in which LINK searches libraries, and the order and
  294. source of the calls in the BSD routines, the following .lod file was the
  295. only one which avoided a LINK prompt for undefined symbols:
  296.  
  297.           * LINK command file to link BSD TimeServ program
  298.           re timeserv.rel
  299.           en
  300.           se
  301.           hpc.lib
  302.           en
  303.  
  304. Second, calls which are looking for an event can execute in either
  305. blocking (execute with wait) or nonblocking (execute without wait) mode.
  306. Blocking means the call will not complete until the event it is looking
  307. for occurs, or there is an error.  Nonblocking means the call completes
  308. immediately, regardless of whether the event occurred, returning a status.
  309. The manual incorrectly states that only nonblocking mode is currently
  310. supported.  Both modes are supported, with blocking mode as the default.
  311. The "Advanced Topics" section of the BSD Manual correctly documents
  312. these modes.
  313.  
  314. Third (not really a "bug"), the use of the term "NULL" in the
  315. documentation needs clarification for the non-C programmer.  Strings in
  316. C must be terminated with a null character (i.e., Char(0)).  However, to
  317. supply a null parameter in a function call, you must supply a zero
  318. (integer) value.
  319.  
  320. Fourth (also not a "bug" but worth mentioning for non-C programmers),
  321. the C language always indexes beginning with 0.  This means that
  322. elements of structures begin with 0, and when the documentation says
  323. that something is the "fourth" element of a structure, it is really the
  324. fifth, but must be accessed using the pointer + 4 because the pointer is
  325. pointing to the 0'th element of the structure.
  326.  
  327.  
  328.  
  329. NOTES:
  330.  
  331. (1) Hewlett-Packard Response Center, Atlanta.  Typical drift rate
  332. observed on the HP9000/433s is +0.3 sec./day.
  333. (2) Hewlett-Packard [users guide]
  334.  
  335.